package com.wzs.rpc.server.tcp;

import cn.hutool.core.util.IdUtil;
import com.wzs.rpc.model.RpcRequest;
import com.wzs.rpc.model.RpcResponse;
import com.wzs.rpc.model.ServiceMetaInfo;
import com.wzs.rpc.protocol.*;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetSocket;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Slf4j
public class VertxTcpClient {
    public static RpcResponse doRequest(RpcRequest rpcRequest,
                                        ServiceMetaInfo serviceMetaInfo,
                                        ProtocolMessageSerializerEnum serializerEnum)
            throws ExecutionException, InterruptedException {
        Vertx vertx = Vertx.vertx();
        // 创建TCP客户端
        NetClient client = vertx.createNetClient();
        //异步获得响应
        CompletableFuture<RpcResponse> rpcResponseFuture = new CompletableFuture<>();
        // 连接到TCP服务器
        client.connect(serviceMetaInfo.getServicePort(), serviceMetaInfo.getServiceHost(),
                result -> {
                    if (result.failed()) {
                        log.error("Failed to connect to TCP server");
                        //handler接口方法并没有声明异常，所以这样抛出的异常不会被调用者处理，因此没作用
//                        throw new RuntimeException("Failed to connect to TCP server");
                        //correct
                        rpcResponseFuture.completeExceptionally(new RuntimeException("Failed to connect to TCP server"));
                        return;
                    }
                    log.info("Connected to TCP server");
                    NetSocket socket = result.result();

                    //构造ProtocolMessage
                    ProtocolMessage.Header header = ProtocolMessage.Header.builder()
                            .magic(ProtocolConstant.PROTOCOL_MAGIC)
                            .version(ProtocolConstant.PROTOCOL_VERSION)
                            .serializer((byte)serializerEnum.getCode())
                            .type((byte) ProtocolMessageTypeEnum.REQUEST.getCode())
                            .requestId(IdUtil.getSnowflakeNextId()) //生成全局唯一ID
                            .build();
                    ProtocolMessage<RpcRequest> rpcRequestProtocolMessage = new ProtocolMessage<>(header, rpcRequest);
                    Buffer requestBuffer = ProtocolMessageEncoder.encode(rpcRequestProtocolMessage);

                    //发送请求
                    try {
                        Buffer buffer = ProtocolMessageEncoder.encode(rpcRequestProtocolMessage);
                        socket.write(buffer);
                    } catch (Exception e) {
                        log.error("协议消息编码错误", e);
                        throw new RuntimeException("协议消息编码错误", e);
                    }

                    //接收响应
                    TcpBufferHandlerWrapper tcpBufferHandlerWrapper = new TcpBufferHandlerWrapper(buffer -> {
                        try {
                            ProtocolMessage<RpcResponse> rpcResponseProtocolMessage = (ProtocolMessage<RpcResponse>) ProtocolMessageDecoder.decode(buffer);
                            rpcResponseFuture.complete(rpcResponseProtocolMessage.getBody());
                        } catch (IOException e) {
                            log.error("协议消息解码错误", e);
                            throw new RuntimeException("协议消息解码错误", e);
                        }
                    });
                    socket.handler(tcpBufferHandlerWrapper);
                });
        //阻塞直到响应完成
        RpcResponse rpcResponse = rpcResponseFuture.get();
        log.info("Received rpcResponse from server: {}", rpcResponse);
        //记得关闭连接
        return rpcResponse;
    }
}